import Taro, { Component } from '@tarojs/taro'
import { View, Text } from '@tarojs/components'
import { connect } from '@tarojs/redux'
import Events from '../../utils/events'

import './style.less'
import Enum from '../../constants/Enum'
import NumKeyboard from '../NumKeyboard'

import { practicePut } from '../../store/actions/practice'


@connect((({ client }) => {
  return client.method
}))
class Baige extends Component {
  static defaultProps = {
    type: {
      value: Enum.addition
    }
  }

  constructor(props) {
    super(props)
    this.state = {
      map: [],  // 二维数组
      cursor: [], // 随机坐标
      index: {}, // 当前坐标
      practiceLog: [], // 练习记录
      input: '', // 用户输入
      startTime: new Date, // 开始答题时间
      practiceSeconds: new Date, // 每一秒
      over: false, // 是否结束
    }
    this.type = ''
    this.timer = null
  }

  componentDidMount () {
    this.initData()
  }
  componentWillReceiveProps(nextProps) {
    if (nextProps.type !== this.props.type) {
      this.initData(nextProps.type)
    }
  }
  initData = (type) => {
    let map = this.getMap(type);
    let cursor = [];
    clearInterval(this.timer)
    const { data } = this.props;
    for (let y = 1; y <= data.y.length; y++) {
      for (let x = 1; x <= data.x.length; x++) {
        if (
          map &&
          map[y] &&
          map[y][x] &&
          map[y][x].disable === false
        ) {
          cursor.push({x, y});
        }
      }
    }
    cursor = cursor.sort(() => Math.random() > .5 ? -1 : 1)
    this.setState({
      map,
      cursor,
      input: '',
      index: null
    }, () => {
      this.getIndex()
    })
  }
  getIndex = (input) => {
    const { cursor, map, index, practiceLog, startTime } = this.state;
    let newMap = [...map];
    let newState = {}
    /*
      1. 找出下一题
      2. 答题
    */
    // 答题
    if (
      index && index.y && index.x && input !== undefined &&
      newMap[index.y] && newMap[index.y][index.x]
    ) {
      let duration = 0
      let time = Date.now()
      if (!this.time) {
        newState.startTime = new Date
        newState.practiceSeconds = new Date
        this.time = setInterval(() => {
          this.setState({
            practiceSeconds: new Date
          })
        }, 1e3)
      }
      newMap[index.y][index.x].isShow = true
      let subject = newMap[index.y][index.x]
      subject.isShow = true;
      subject.isCorrect = input === subject.result ? 'yes' : 'no';
      subject.userInput = input;
      subject.result = input;
      newState.map = newMap;
      // 收集答题记录
      let newSubject = {
        ...subject,
        input
      };
      delete newSubject.isShow;
      if (practiceLog.length) {
        duration = parseFloat(
          (time - practiceLog[practiceLog.length - 1].time) / 1000
        )
      } else {
        duration = parseFloat((time - startTime) / 1000)
      }
      duration = Math.floor(duration * 100) / 100
      practiceLog.push({
        ...newSubject,
        time,
        duration,
      })
      newState.practiceLog = practiceLog;
    }

    // 找到下一个
    if (
      Array.isArray(cursor) && cursor.length &&
      (index === null || input !== undefined)
    ) {
      let newIndex = {...cursor[0]};
      cursor.shift();
      newState.map = newMap;
      newState.cursor = cursor;
      newState.index = newIndex;
    } else {
      newState.over = true;
      const { dispatch, data } = this.props;
      dispatch(practicePut(practiceLog, data.category));
      Events.trigger('over')
    }
    this.setState(newState);
  }

  addition = (n1, n2) => n1 + n2
  subtraction = (n1, n2) => n1 - n2
  multiplication = (n1, n2) => n1 * n2
  division = (n1, n2) => {
    if (n1 === 0 || n2 === 0) {
      return -1
    }
    return Math.floor((n1 / n2) * 100) / 100
  }

  subjectFilter = (subject) => {
    /*
      +
        0-9 结果 > 10 过滤
      -
        结果 < 0 过滤
    */
    const { range, type } = this.props;
    let newSubject = {...subject};
    if (
      type === Enum.addition &&
      range === Enum.range_0_9 &&
      newSubject.result > 10
    ) {
      newSubject.disable = true;
    } else if (
      type === Enum.subtraction &&
      newSubject.result < 0 || newSubject.result === Infinity
    ) {
      newSubject.disable = true;
    }
    return newSubject;
  }

  getMap = (newType) => {
    const { data: { x, y } } = this.props;
    let type = {}
    if (newType) {
      type = newType;
    } else {
      type = this.props.type;
    }
    this.type = type
    let method = this.addition;
    let map = [];

    switch (type) {
      case Enum.addition:
        method = this.addition;
        break;
      case Enum.subtraction:
        method = this.subtraction;
        break;
      case Enum.multiplication:
        method = this.multiplication;
        break;
      case Enum.division:
        method = this.division;
        break;
      default:
        method = this.addition;
        break;
    }
    let self = this
    map = y.map(col => {
      let arr = x.map(row => {
        let result = method(col , row)
        let subject = {
          result,
          x: row,
          y: col,
          disable: false,
          isShow: false,
          formula: `${col}${type}${row}`,
          isCorrect: 'none', // none 还没解答, yes 答对, no 答错
          type: 'point',
        }
        return self.subjectFilter(subject)
      })
      return arr;
    })
    map.unshift([type, ...x]);
    map = map.reduce((res, item, i) => {
      if (i > 0) {
        item.unshift(y[i - 1]);
      }
      res.push(item);
      return res;
    }, [])
    return map;
  }
  numPadding = (num) => {
    if (num < 10) {
      return `0${num}`
    }
    return num
  }
  getLocalTime = (value) => {
    let secondsTime = parseInt(value);
    let minuteTime = 0;
    let hourTime = 0;
    if (secondsTime > 60) {
      minuteTime = parseInt(secondsTime / 60);
      secondsTime = parseInt(secondsTime % 60);
      if (minuteTime > 60) {
        hourTime = parseInt(minuteTime / 60);
        minuteTime = parseInt(minuteTime % 60);
      }
    }
    if (hourTime < 0) {
      return `${this.numPadding(hourTime)}:${this.numPadding(minuteTime)}:${this.numPadding(secondsTime)}`;
    }
    return `${this.numPadding(minuteTime)}:${this.numPadding(secondsTime)}`;
  }
  render() {
    const { map, index, cursor, input, over, practiceSeconds, startTime } = this.state
    let seconds = parseInt(Math.floor(practiceSeconds - startTime) / 1000)
    return (
      <View className='baige-content' >
        {
          seconds == 0 ? (
            <View className='time'><Text>00:00</Text></View>
          ) :(
            <View className='time'>已过去<Text>{this.getLocalTime(seconds)}</Text></View>
          )
        }
        {
          (!over || true) && (
            <View className='baige' >
              {
                (Array.isArray(map) && map.length) && map.map((col, colKey)=> {
                  return (
                    <View key={colKey} className='tr' >
                      {
                        col.map((row, rowKey) => {
                          let point = map[colKey][rowKey]
                          let result = ''
                          let style = {}
                          let className = 'td'
                          if (point.type === 'point') {
                            if (point.disable) {
                              result = 'x'
                              style = {background: '#eee'}
                            } else if (point.isShow) {
                              result = point.result
                              if (point.isCorrect == 'no') {
                                className+=' err'
                              }
                            }
                          } else {
                            result = point
                          }
                          if (cursor.length && index) {
                            if (index.y === colKey && index.x > rowKey-1) {
                              className += ' active'
                            } else if (index.y > colKey-1 && index.x === rowKey) {
                              className += ' active'
                            }
                          }
                          return (
                            <View key={rowKey} className={className} style={style} >
                              {result}
                            </View>
                          )
                        })
                      }
                    </View>
                  )
                })
              }
            </View>
          )
        }
        <NumKeyboard
          onNext={this.getIndex}
          input={input}
          index={map[index.y][index.x]}
        />
      </View>
    )
  }
}

export default Baige
